package bb.lanxing.calc.calculator;

import com.github.mikephil.charting.utils.Utils;
import bb.lanxing.calc.data.SourcePoint;
import bb.lanxing.manager.RemoteSharedPreference;
import bb.lanxing.manager.SPConstant;
import bb.lanxing.model.database.Workout;
import bb.lanxing.util.DistanceUtil;
import bb.lanxing.util.LimitedLinkedList;
import bb.lanxing.util.Log;

public class ElevationGradeCalc {
    final static private String TAG = "ElevationGradeCalc";
    private static final float ELEVATION_OFFSET = 0.2f;
    private static final float GRADE_MAX = 20.0f;
    private static final double GRADE_MIN_DISTANCE = 8.0d;
    private static final int GRADE_MIN_POINT_COUNT = 4;
    private static final float INVALID_ALTITUDE = -50000.0f;
    private static final double SEGMENT_DISTANCE_CYCLING = 350.0d;
    private static final double SEGMENT_DISTANCE_RUNNING = 200.0d;
    private static final double SEGMENT_DISTANCE_WALKING = 150.0d;
    private float elevation;
    private float grade;
    private double segAltitudeSum;
    private int segCount;
    private double segDistanceSum;
    private LimitedLinkedList<SourcePoint> locQueue = new LimitedLinkedList<>(8);
    private double segMinAltitude = -50000.0d;
    private double segMaxAltitude = -50000.0d;
    private float lastAvgAltitude = INVALID_ALTITUDE;
    private final float SMOOTH_FACTOR = 0.2f;
    private final float SMOOTH_FACTOR_INV = 0.8f;

    private float smooth(float last, float current) {
        return (current * SMOOTH_FACTOR) + (last * SMOOTH_FACTOR_INV);
    }

    public void calc(SourcePoint sourcePoint) {
        this.locQueue.add(sourcePoint);
        calcElevation();
        calcGrade();
    }

    private void calcGrade() {
        LimitedLinkedList<SourcePoint> limitedLinkedList = this.locQueue;
        float f = 0.0f;
        if (limitedLinkedList != null) {
            int i = 2;
            if (limitedLinkedList.size() >= 2) {
                SourcePoint sourcePoint = null;
                SourcePoint last = this.locQueue.getLast();
                int size = this.locQueue.size();
                int i2 = 1;
                double d = 0.0d;
                while (true) {
                    if (i2 >= size) {
                        break;
                    }
                    d = DistanceUtil.get(last, this.locQueue.get((size - 1) - i2));
                    i = i2 + 1;
                    if (d > GRADE_MIN_DISTANCE && i >= GRADE_MIN_POINT_COUNT) {
                        sourcePoint = this.locQueue.get(i2);
                        break;
                    }
                    i2 = i;
                }
                if (d == Utils.DOUBLE_EPSILON || sourcePoint == null) {
                    smoothGrade(0.0f);
                    return;
                }
                Log.v(TAG, "calcGrade, distance = " + d + ", size = " + size + ", count = " + i);
                float altitude = (float) (last.getAltitude() - sourcePoint.getAltitude());
                StringBuilder sb = new StringBuilder();
                sb.append("calcGrade, offset = ");
                sb.append(altitude);
                Log.v(TAG, sb.toString());
                if (Math.abs(altitude) > ELEVATION_OFFSET && d > GRADE_MIN_DISTANCE) {
                    f = (float) ((altitude / d) * 100.0d);
                    Log.v(TAG, "calcGrade, curGrade = " + f);
                    if (Math.abs(f) > GRADE_MAX) {
                        f = this.grade;
                    }
                }
                smoothGrade(f);
                return;
            }
        }
        smoothGrade(0.0f);
    }

    private void calcElevation() {
        LimitedLinkedList<SourcePoint> limitedLinkedList = this.locQueue;
        Log.d(TAG, "calcElevation.....");
        if (limitedLinkedList == null || limitedLinkedList.size() < 2) {
            this.elevation = 0.0f;
            Log.d(TAG, "calcElevation.....000");
            return;
        }

        SourcePoint last = this.locQueue.getLast();
        LimitedLinkedList<SourcePoint> limitedLinkedList2 = this.locQueue;
        double d = DistanceUtil.get(last, limitedLinkedList2.get(limitedLinkedList2.size() - 2));
        double altitude = last.getAltitude();
        this.segDistanceSum += d;
        this.segAltitudeSum += altitude;
        Log.d(TAG, "calcElevation.....segDistanceSum=" + segDistanceSum + ", segAltitudeSum=" + segAltitudeSum);

        if (Math.abs(this.segMinAltitude - INVALID_ALTITUDE) < Utils.FLOAT_EPSILON) {
            Log.d(TAG, "calcElevation...segMinAltitude INVALID_ALTITUDE");
            this.segMinAltitude = altitude;
        } else {
            this.segMinAltitude = Math.min(this.segMinAltitude, altitude);
        }

        if (Math.abs(this.segMaxAltitude - INVALID_ALTITUDE) < Utils.FLOAT_EPSILON) {
            Log.d(TAG, "calcElevation...segMaxAltitude INVALID_ALTITUDE");
            this.segMaxAltitude = altitude;
        } else {
            this.segMaxAltitude = Math.max(this.segMaxAltitude, altitude);
        }
        Log.d(TAG, "calcElevation...segMinAltitude=" + segMinAltitude + ", segMaxAltitude=" + segMaxAltitude);

        this.segCount++;
        Log.d(TAG, "calcElevation, segDistanceSum = " + this.segDistanceSum);
        if (this.segDistanceSum > getSegmentDistance()) {
            Log.d(TAG, "calcElevation...segCount=" + segCount + ", segAltitudeSum=" + segAltitudeSum);
            if (segCount > 2) {
                segAltitudeSum = segAltitudeSum - segMinAltitude - segMaxAltitude;
                segCount -= 2;
            }
            float vAverageAltitude = (float) (segAltitudeSum / segCount);

            if (Math.abs(this.lastAvgAltitude - INVALID_ALTITUDE) < Utils.FLOAT_EPSILON) {
                Log.d(TAG, "calcElevation...lastAvgAltitude INVALID_ALTITUDE");
                this.elevation = 0.0f;
            } else {
                this.elevation = vAverageAltitude - lastAvgAltitude;
            }

            Log.d(TAG, "calcElevation, elevation = " + elevation
                    + ", new vAverageAltitude = " + vAverageAltitude + ", lastAvgAltitude = " + lastAvgAltitude);
            this.lastAvgAltitude = vAverageAltitude;
            this.segDistanceSum = Utils.DOUBLE_EPSILON;
            this.segAltitudeSum = Utils.DOUBLE_EPSILON;
            this.segMinAltitude = INVALID_ALTITUDE;
            this.segMaxAltitude = INVALID_ALTITUDE;
            this.segCount = 0;
        } else {
            this.elevation = 0.0f;
            Log.d(TAG, "calcElevation, segAltitudeSum = " + this.segAltitudeSum + ", segCount = " + this.segCount);
        }
    }

    private void smoothGrade(float curGrade) {
        this.grade = smooth(this.grade, curGrade);
    }

    private double getSegmentDistance() {
        int vSportType = RemoteSharedPreference.getInstance().getInt(SPConstant.KEY_SPORT_TYPE, Workout.TYPE_CYCLING);
        Log.d(TAG, "getSegmentDistance vSportType=" + vSportType);
        if (vSportType == Workout.TYPE_WALKING) {
            return SEGMENT_DISTANCE_WALKING;
        } else if (vSportType == Workout.TYPE_RUNNING) {
            return SEGMENT_DISTANCE_RUNNING;
        } else {
            return SEGMENT_DISTANCE_CYCLING;
        }

    }

    public float getElevation() {
        return this.elevation;
    }

    public float getGrade() {
        return this.grade;
    }

    public void reset() {
        this.locQueue.clear();
        this.lastAvgAltitude = 0.0f;
        this.segDistanceSum = Utils.DOUBLE_EPSILON;
        this.segAltitudeSum = Utils.DOUBLE_EPSILON;
        this.segMinAltitude = INVALID_ALTITUDE;
        this.segMaxAltitude = INVALID_ALTITUDE;
        this.segCount = 0;
        this.elevation = 0.0f;
        this.grade = 0.0f;
    }
}
